module shifter(
  input  [ 2:0] i_op,
  input  [31:0] i_rm,
  input         i_carry,
  input  [ 4:0] i_shamt,
  input  [ 7:0] i_rs,
  output [31:0] o_rm_shifted,
  output        o_carry
);

wire [5:0] shamtw; // 1..32

reg [31:0] y; // comb logic
reg  c; // comb logic

assign shamtw = {~|i_shamt, i_shamt};

assign o_rm_shifted = y;
assign o_carry = c;

wire [32:0] lsl_out;
wire [32:0] lsr_out;
wire [32:0] asr_out;
wire [32:0] ror_out;

wire [7:0] lslamt = i_op[0] ? i_rs      : {3'b0, i_shamt } ;
wire [7:0] lsramt = i_op[0] ? i_rs      : {2'b0,   shamtw} ;
wire [4:0] roramt = i_op[0] ? i_rs[4:0] :        i_shamt   ;

lsl u_lsl(
  .in({i_carry, i_rm}),
  .sh(lslamt),
  .out(lsl_out)
);

lsr u_lsr(
  .in({i_rm, i_carry}),
  .sh(lsramt),
  .out(lsr_out)
);

asr u_asr(
  .in({i_rm, i_carry}),
  .sh(lsramt),
  .out(asr_out)
);

ror u_ror(
  .in(i_rm),
  .sh(roramt),
  .out(ror_out[32:1]),
  .cout(ror_out[0])
);

always @* begin
  casez (i_op)
    /* LSL */
    3'b00?: {c, y} = lsl_out;
    /* LSR */
    3'b01?: {y, c} = lsr_out;
    /* ASR */
    3'b10?: {y, c} = asr_out;
    /* ROR #<shift_imm> */
    3'b110: {y, c} = |i_shamt ? ror_out : {i_carry, i_rm[31:1], i_rm[0]};
    /* ROR <Rs> */
    3'b111: begin
      y = ror_out[32:1];
      c = |i_rs[7:0] ? ror_out[0] : i_carry;
    end
  endcase
end

endmodule
